#include "General_GUI.h"
#include <math.h>
#include <stdio.h>

void General_GUI::drawVLine(int x, int y, int h)
{
	for (int i = 0; i < h; i++)
	{
		if (y + i >= height)
		{
			return;
		}
		drawPixel(x, y + i);
	}
}

void General_GUI::drawHLine(int x, int y, int w)
{
	for (int i = 0; i < w; i++)
	{
		if (x + i >= width)
		{
			return;
		}
		drawPixel(x + i, y);
	}
}

void General_GUI::drawRect(int x, int y, int w, int h)
{
	drawVLine(x, y, h);
	drawHLine(x, y, w);
	drawHLine(x, y + h - 1, w);
	drawVLine(x + w - 1, y, h);
}

void General_GUI::fillRect(int x, int y, int w, int h)
{
	for (int i = 0; i < h; i++)
	{
		if (y + i >= height)
		{
			return;
		}
		drawHLine(x, y + i, w);
	}
}

void General_GUI::drawCircle(int x, int y, int r)
{
	for (int i = 0; i <= r; i++)
	{
		int draw_y, draw_x;
		draw_y = (int)(sqrt(double(r * r - i * i)) + 0.5);
		draw_x = i;
		drawPixel(x + draw_x, y + draw_y);
		drawPixel(x - draw_x, y + draw_y);
		drawPixel(x + draw_x, y - draw_y);
		drawPixel(x - draw_x, y - draw_y);
		drawPixel(x + draw_y, y + draw_x);
		drawPixel(x - draw_y, y + draw_x);
		drawPixel(x + draw_y, y - draw_x);
		drawPixel(x - draw_y, y - draw_x);
		//drawPixel(draw_y, draw_x);
	}
}

void General_GUI::drawLine(int begin_x, int begin_y, int end_x, int end_y)
{
	double k, b; //y=kx+b //x=(y-b)/k
	k = (double)(end_y - begin_y) / (double)(end_x - begin_x);
	b = (double)end_y - k * (double)end_x;

	if (end_x > begin_x)
	{
		for (int x = begin_x; x <= end_x; x++)
		{
			double y = k * x + b;
			drawPixel(x, (int)(y + 0.5));
		}
	}
	else
	{
		for (int x = end_x; x <= begin_x; x++)
		{
			double y = k * x + b;
			drawPixel(x, (int)(y + 0.5));
		}
	}

	if (end_y > begin_y)
	{
		for (int y = begin_y; y <= end_y; y++)
		{
			double x = (double(y) - b) / k;
			drawPixel((int)(x + 0.5), y);
		}
	}
	else
	{
		for (int y = end_y; y <= begin_y; y++)
		{
			double x = (double(y) - b) / k;
			drawPixel((int)(x + 0.5), y);
		}
	}
}

size_t General_GUI::write(uint8_t assci)
{
	if (assci == '\n')
	{
		posx = 0;
		posy += GUI_font->font_height;
		return 1;
	}
	if (assci < ' ' || assci > '~')
	{
		assci = 32;
	}
	assci -= 32;

	int write_width, write_height, write_mode_size;
	write_width = GUI_font->font_width;
	write_height = GUI_font->font_height;
	write_mode_size = GUI_font->mode_size;

	const uint8_t *assci_ptr = GUI_font->font_ptr + assci * write_mode_size;

	if (posx + write_width >= 128)
	{
		posx = 0;
		posy += write_height;
	}

	for (int i = 0; i < write_mode_size; i++)
	{
		for (int j = 0; j < 8; j++)
		{
			uint8_t bit_data = assci_ptr[i] & (1 << j);
			if (bit_data)
			{
				drawPixel((i % write_width) + posx, (i / write_width) * 8 + j + posy);
			}
		}
	}

	posx += (1 + write_width);
	return 1;
}

size_t General_GUI::write(const uint8_t *str, size_t size)
{
	for (int i = 0; i < size; i++)
	{
		write(str[i]);
	}
	return 1;
}

void General_GUI_Bin::drawPixel(int x, int y)
{
	if (x >= width || y >= height)
	{
		return;
	}
	img_data[(y / 8) * width + x] |= (uint8_t)(1 << (y % 8));
}

void General_GUI_Bin::clear_img()
{
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height / 8; j++)
		{
			img_data[j * width + i] = 0x00;
		}
	}
}

void General_GUI_Bin::fill(int data)
{
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height / 8; j++)
		{
			img_data[j * width + i] = (uint8_t)data;
		}
	}
}
